#include "proto/rpcserver.pb.h"

#include "../server/base/Utils.h"
#include "../server/base/CurrentOfThread.h"
#include "protorpc/RpcCodec.h"

#include "../server/net/EventLoop.h"
#include "../server/thread/CountDownLatch.h"
#include "../server/logging/Logging.h"
#include "../server/net/EventLoopThreadPool.h"
#include "../server/net/EventLoopThread.h"
#include "../server/net/InetAddress.h"
#include "../server/net/TcpClient.h"
#include "../server/net/TcpConnection.h"
#include "protorpc/RpcChannel.h"

#include <stdio.h>
#include <unistd.h>

using namespace yhaida;

static const int kRequests = 50;

class RpcClient : Utils::nocapyable
{
public:
    RpcClient(EventLoop *loop,
              const InetAddress &serverAddr)
        : _client(loop, serverAddr),
          _channel(new rpc::RpcChannel()),
          _echoStub(get_pointer(_channel)),
          _rpcStub(get_pointer(_channel))
    {
        _client.setConnectionCallback(
            std::bind(&RpcClient::onConnection, this, _1));
        _client.setMessageCallback(
            std::bind(&rpc::RpcChannel::onMessage, get_pointer(_channel), _1, _2, _3));
    }

    void connect()
    {
        _client.connect();
    }
    void disconnect()
    {
        _client.disconnect();
    }

    void sendEchoRequest(std::string msg)
    {
        rpc::EchoRequest request;
        request.set_payload(msg);
        rpc::EchoResponse *response = new rpc::EchoResponse;
        _echoStub.Echo(NULL, &request, response, NewCallback(this, &RpcClient::echoShow, response));
    }
    void sendListenRequest()
    {
        rpc::ListRpcRequest request;
        rpc::ListRpcResponse *response = new rpc::ListRpcResponse;
        _rpcStub.listRpc(NULL, &request, response, NewCallback(this, &RpcClient::ListenRPCShow, response));
    }
    void sendgetServiceRequest(std::string msg)
    {
        //拼接lua函数
        std::string rpc_function = "function __rpc_function()\n";
        rpc_function += "return " + msg + "\n";
        rpc_function += "end\n";
        rpc::GetServiceRequest request;
        request.set_function(rpc_function);
        rpc::GetServiceResponse *response = new rpc::GetServiceResponse;
        _rpcStub.getService(NULL, &request, response, NewCallback(this, &RpcClient::getServiceShow, response));
    }

private:
    void onConnection(const TcpConnectionPtr &conn)
    {
        if (conn->connected())
        {
            _channel->setConnection(conn);
            conn->setTcpNoDelay(true);
        }
    }

    void echoShow(rpc::EchoResponse *response)
    {
        LOG_INFO << "\n\n" << ">>" <<response->DebugString()<<"\n";

    }

    void ListenRPCShow(rpc::ListRpcResponse *response)
    {
        LOG_INFO << "\n\n" << ">>" <<response->DebugString()<<"\n";
    }

    void getServiceShow(rpc::GetServiceResponse *response)
    {
        LOG_INFO << "\n\n" << ">>" <<response->DebugString()<<"\n";
    }

private:
    //客户端
    TcpClient _client;
    // Rpc
    rpc::RpcChannelPtr _channel;

    yhaida::rpc::EchoService_Stub _echoStub;
    yhaida::rpc::RpcService_Stub _rpcStub;
};
int main(int argc, char *argv[])
{
    uint16_t port = static_cast<uint16_t>(8000);
    InetAddress serverAddr("127.0.0.1", port);

    EventLoopThread loopThread;
    RpcClient client(loopThread.startLoop(), serverAddr);
    client.connect();

    std::string line;
    printf("please input:<cmd> <param> ...");
	while (std::getline(std::cin, line))
    {	
		int pos = line.find(' ');

		std::string cmd;
		cmd = line.substr(0,pos++);
		std::string param = line.substr(pos);
		if(cmd == "echo")//指令格式 $echo "Hello World!"
		{
			printf("%s",param.c_str());
            client.sendEchoRequest(param);
            
		}
		else if(cmd == "show")//指令格式  $show
		{
            printf("show");
			client.sendListenRequest();
		}
		else if(cmd == "comm")//指令格式  $comm <service> <param> ......
		{
            printf("%s",param.c_str());
            client.sendgetServiceRequest(param);
		}
		else
		{
            printf("erro!");
		}
		printf("please input:<cmd> <param> ...\n");
    }

    client.disconnect();
    CurrentOfThread::sleepUsec(1000*1000);
}